home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / PROGRAMM / CC_C / 0924.ZIP / TCED < prev   
Text File  |  1988-01-10  |  30KB  |  942 lines

  1.  
  2. /*    -------------  ASCII FILE SCREEN EDITOR     ---------------
  3.  
  4.       Requires MSDOS 3 and ANSI.SYS    for cursor positioning.
  5.       Uses direct output to    text mode video    RAM at B800:0.
  6.       Reassigns stdin and stdout to    avoid redirection.
  7.       Compile (under SMC) with options -F -D62 and -S1.
  8. */
  9.  
  10. #include <smio.h>
  11.  
  12. /* General definitions */
  13. #define       TCLR        2     /* keys to clear       */
  14. #define       TABS        4     /* tab column pitch  */
  15. #define       TWID           32     /* command width       */
  16. #define       WIDTH       78     /* text line width   */
  17. #define       TOPROW    3     /* display top line  */
  18. #define       ENDROW      25     /* display end line  */
  19. #define       QBSIZE     512     /* input buffer size */
  20. #define       RCHAR    '\257'    /* find/replace char */
  21. #define       EXFILE  "EXTRACT"  /* default file name */
  22.  
  23. /* Screen edit action key assignments -    the settings
  24.    below are for the standard Amstrad PC1512 keyboard */
  25.  
  26. /* The function    key settings are:
  27.      F1: Set for/leave external command, or
  28.          set search/replace    string;
  29.    Shift F1: Quit;
  30.      F2: Insert buffer lines;
  31.    Shift F2: Delete lines to buffer;
  32.      F3: Append following line;
  33.    Shift F3: Break line    at cursor;
  34.      F4: Beginning of line/top of page;
  35.    Shift F4: End of line;
  36.    Shift F5: Save edit;
  37.      F6: Move to next line;
  38.    Shift F6: Delete to end of line;
  39.      F7: Move to mark;
  40.    Shift F7: Set mark;
  41.      F8: Search/replace;
  42.      F9: Move to next word;
  43.     F10: Refresh screen.
  44. */
  45.  
  46. #define       KLDEL      0x08     /* <-delete    */
  47. #define       KRDEL      0x07     /* delete->    */
  48. #define       KESC          0x1B     /* escape    */
  49. #define       KEOF          0x4F00   /* end of file    */
  50. #define       KTOP          0x4700   /* top of file    */
  51. #define       KCUP          0x4800   /* cursor up    */
  52. #define       KCDN          0x5000   /* cursor down    */
  53. #define       KCLF          0x4B00   /* cursor left    */
  54. #define       KCRT          0x4D00   /* cursor right    */
  55. #define       KTAB          0x09     /* tab        */
  56. #define       KRET          0x0D     /* return    */
  57. #define       KSCUP      0x4900   /* screen up    */
  58. #define       KSCDN      0x5100   /* screen down    */
  59. #define       KINS          0x5200   /* insert toggle    */
  60. #define       KQAC          0x3E00   /* Q action    */
  61. #define       KTLIN      0x3B00   /* command key    */
  62. #define       KCONC      0x3D00   /* join lines    */
  63. #define       KBDEL      0x5500   /* delete lines    */
  64. #define       KBRES      0x3C00   /* restore lines    */
  65. #define       KRFSH      0x4400   /* screen reset    */
  66. #define       KCEOL      0x5700   /* cursor eol    */
  67. #define       KDEOL      0x5900   /* delete eol    */
  68. #define       KTWRD      0x4300   /* tab to word    */
  69. #define       KMARK      0x5A00   /* set mark    */
  70. #define       KGOMK      0x4100   /* go to    mark    */
  71. #define       KSRCH      0x4200   /* find/alter    */
  72. #define       KQUIT      0x5400   /* quit edit    */
  73. #define       KSAVE      0x5800   /* save edit    */
  74. #define       KF3          0x5600   /* line break    */
  75. #define       KF6          0x4000   /* next line    */
  76.  
  77.  
  78. /* Structure typedefs */
  79. typedef    struct { char *qnx, *qnd; int qfd; char    qbb [QBSIZE]; }    qbuf;
  80. typedef    struct mbk { struct mbk    *lptr, *rptr;  unsigned    size; }    mtag;
  81.  
  82.  
  83. /* Global data */
  84. mtag    bfend[2], bfstt[2], base, *sline, *eline,
  85.     *bfe = bfend,  *bfs = bfstt, *last = NULL,
  86.     *mline = NULL, *sdel = NULL, *cdel = NULL;
  87.  
  88. char    edbuf [6 + 2 * WIDTH], cmdbuf [4 + TWID], schbuf [4 + TWID],
  89.     *mark =    "<<< - MARK - >>>", *endz = edbuf + WIDTH, *scename;
  90.  
  91. int    xcur, ycur, tcur, dircc, bfull = 0, rfull = 0, clrct = 0,
  92.     eflag =    0, iflag = 1, pflag = 0, cflag = 0, tflag = 0;
  93.  
  94.  
  95. /* Main    - initialise for edit */
  96.  
  97. main (argc, argv) int argc; char *argv[];
  98.      {    static int e;
  99.  
  100.     /* Reassign MSDOS stdin    and stdout */
  101.     if ((e = open ("CON", 2)) != -1)
  102.     {  reopen (_fdsin, e); reopen (_fdsout,    e); }
  103.  
  104.     /* Initialise edit buffer pointers */
  105.     cls (1); nalloc    (0);
  106.     bfs->lptr = bfs; bfs->rptr = bfe;
  107.     bfe->lptr = bfs; bfe->rptr = bfe;
  108.  
  109.     scename    = (argc    > 1) ? *++argv : "WORK";
  110.  
  111.     cmdloop(); cls (1); } /* End of    main */
  112.  
  113.  
  114. /* Edit    and command loop */
  115.  
  116. cmdloop()
  117.      {    static int sce,    c, k; static char *s;
  118.     static mtag *p,    *q, *r;
  119.  
  120.     /* Read    the source file    */
  121.     sce = bopen (0,    scename); setscr();
  122.     xcur = 1; ycur = TOPROW; scrloc();
  123.     if (sce    != NULL) rdfile    (&sce, bfe);
  124.     else { toptxt ("New file."); bell(); }
  125.     sline =    bfs->rptr;
  126.  
  127.     while (1)
  128.  
  129.     {  keyedit();
  130.  
  131.        if (match (cmdbuf, "more"))
  132.        {  if (!sce)    toptxt ("None left.");
  133.           else rdfile (&sce, bfe); continue; }
  134.  
  135.        if (k = match (cmdbuf, "insert"))
  136.        {  s    = cmdbuf + k;
  137.           if ((k = bopen (1, (*s) ?    s : EXFILE)) ==    NULL)
  138.           {     toptxt    ("Cannot open."); continue; }
  139.           cset(); q    = curline();
  140.           if (q == bfe) q =    bufins ("\0", bfe);
  141.           rdfile (&k, q->rptr);
  142.           redis (q); continue; }
  143.  
  144.        if ((k = match (cmdbuf, "store")) ||
  145.            (k = match (cmdbuf, "extract")))
  146.        {  if (mline    == NULL) { toptxt ("No mark.");    continue; }
  147.           if ((q = curline()) == mline || q->rptr == mline)
  148.           {    toptxt ("Nothing to save."); continue; }
  149.           s    = cmdbuf + k; s    += (k =    match (s, "\\s"));
  150.           r    = bfs->rptr; while (r != q && r    != mline) r = r->rptr;
  151.           if (fsave    ((*s) ?    s : EXFILE, r->rptr,
  152.              r == q    ? mline    : q->rptr, k) == 0) topclr();
  153.           if (match    (cmdbuf, "extract") && qcheck()) return;
  154.           continue;    }
  155.  
  156.        if (match (cmdbuf, "delete"))
  157.        {  if (mline    == NULL) { toptxt ("No mark.");    continue; }
  158.           cset(); pflag = 0; q = curline();
  159.           r    = bfs->rptr; while (r != q && r    != mline) r = r->rptr;
  160.           if (r == mline) {    p = q->rptr; q = r->lptr; }
  161.           else { r = r->rptr; p = mline->rptr; }
  162.           while (r != p)
  163.           {     r->lptr->rptr = r->rptr;
  164.          r->rptr->lptr = r->lptr;
  165.          nfree (r); r =    r->rptr; }
  166.           mline = 0; redis (q); nprin(); continue; }
  167.  
  168.        if (match (cmdbuf, "quit"))
  169.        {  if (qcheck()) return;
  170.           continue;    }
  171.  
  172.        if (k = match (cmdbuf, "end"))
  173.        {  s    = cmdbuf + k; s    += (k =    match (s, "\\s"));
  174.           if (!cflag && !*s) return;
  175.           if (sce != NULL) { toptxt    ("Source unfinished.");    continue; }
  176.           if (fsave    ((*s) ?    s : scename, bfs->rptr,
  177.              bfe, k) == -1)    continue;
  178.           return; }
  179.  
  180.        /* Unknown command */
  181.        cls (1); dirloc (1, 1); putstr (cmdbuf);
  182.        putstr (" >\n"); system (cmdbuf);
  183.        putstr ("\nPress any    key to return to Edit: ");
  184.        getch(); cls    (0); continue;
  185.  
  186.        } } /* End of cmdloop */
  187.  
  188. /* Check for quit */
  189. qcheck()
  190.      {    static char c;
  191.     if (!cflag) return 1;
  192.     toptxt ("Confirm QUIT (Y/N): ");
  193.     c = getch(); topclr();
  194.     return (c == 'y' || c == 'Y'); }
  195.  
  196. /* Match a command */
  197. match (b, t) char *b, *t;
  198.      {    static int c; static char *s; s    = b;
  199.     while (*s == ' ') ++s;
  200.     while (*t)
  201.     { if ((c = *s) >= 'A' && c <= 'Z') c +=    0x20;
  202.       if (c    != *t) return 0;  ++s; ++t; }
  203.     if (*s && *s !=    ' ') return 0;
  204.     while (*s == ' ') ++s;
  205.     return s - b; }
  206.  
  207.  
  208. /* Key-stroke edit functions - xcur, ycur and sline set    on entry;
  209.    performs all    single-key edit    functions; command buf set on exit */
  210.  
  211. keyedit()
  212.      {    static int c, f, i, k, v;
  213.     static mtag *q,    *r;
  214.     static char *s,    *t, *u;
  215.  
  216.     setscr(); raster (TOPROW); nprin();
  217.  
  218.     while (1)
  219.  
  220.     {  c = getch();    if (clrct && !--clrct) topclr();
  221.  
  222.        /* Normal character entry */
  223.        if (c >= 0x20 && c <= 0x7E)
  224.        {  if (tflag) { if (tcur >= TWID) bell();
  225.                else    { edbuf    [tcur++] = c; topdis();    }
  226.                continue; }
  227.           if (curline() == mline) {    bell();    continue; }
  228.           if (testful (0)) continue;
  229.           edset(); v = 0; f    = setzz    (&s, xcur, 1);
  230.           if (!f &&    iflag)
  231.           {     setrc (&t, s);    *t = 0;
  232.          if (t >= endz)
  233.          { t = endz; *--t = 0; v = 1; }
  234.          do *(t+1) = *t; while (--t >= s); }
  235.           *s = c; if (f) *(s+1) = 0;
  236.           dirloc (xcur, ycur); dirstr (s);
  237.           if (xcur < WIDTH)    ++xcur;    else v = 1;
  238.           if (v) bell(); scrloc(); continue; }
  239.  
  240.        switch (c)  /* Topline entry    actions    */
  241.  
  242.        {   case KTOP: /* top of file */
  243.           edcheck(); undel(); xcur = 1;    ycur = TOPROW;
  244.           sline    = bfs->rptr; raster (TOPROW); break;
  245.  
  246.            case KEOF: /* end of file */
  247.           sline    = bfe; xcur = 1; ycur =    ENDROW;
  248.          /* Continue as    up screen */
  249.  
  250.            case KSCUP: /* up screen    */
  251.           edcheck(); undel();
  252.           for (i = TOPROW; i < ENDROW; i++)
  253.           if (sline->lptr != bfs) sline    = sline->lptr;
  254.           raster (TOPROW); break;
  255.  
  256.            case KSCDN: /* down screen */
  257.           edcheck(); undel();
  258.           for (q = sline, i = TOPROW;
  259.                i < ENDROW; i++)    q = q->rptr;
  260.           sline    = (q ==    bfe) ? sline : q;
  261.           raster (TOPROW); break;
  262.  
  263.            case KCLF: /* left cursor */
  264.           if (xcur > 1)    --xcur;    scrloc(); break;
  265.  
  266.            case KCRT: /* right cursor */
  267.           if (xcur < WIDTH) ++xcur; scrloc(); break;
  268.  
  269.            case KCDN: /* down cursor */
  270.           dncurs(); break;
  271.  
  272.            case KCUP: /* up    cursor */
  273.           edcheck(); undel();
  274.           if (ycur > TOPROW) --ycur;
  275.           else if (sline != bfs->rptr)
  276.             {  dirlins (TOPROW); dirloc(1, TOPROW);
  277.                dirstr ((sline = sline->lptr) + 1); }
  278.           scrloc(); break;
  279.  
  280.            case KESC:  /* find/replace or end of line */
  281.           if (tflag) { edbuf [tcur++] =    RCHAR;
  282.                    topdis(); break;    }
  283.           /* Continue as end of    line */
  284.  
  285.            case KCEOL: /* Cursor end of line */
  286.           edcheck(); q = curline();
  287.           for (i = 1, t    = q + 1; *t; ++t)
  288.             i += (*t < 0x20) ? *t : 1;
  289.           xcur = i; scrloc(); break;
  290.  
  291.            case KLDEL: /* <-delete */
  292.           if (tflag) { if (tcur    > 1)
  293.                    { --tcur; topdis(); } break; }
  294.           if (curline()    == mline) { bell(); break; }
  295.           if (xcur == 1) break;
  296.           --xcur; scrloc(); /* Continue    as delete-> */
  297.  
  298.            case KRDEL: /* delete-> */
  299.           if (tflag) break;
  300.           if ((q = curline()) == bfe) break;
  301.           if (q    == mline) { bell(); break; }
  302.           edset(); f = setzz (&s, xcur,    0);
  303.           if (!f) {  t = s+1; while (*(t-1) = *t) ++t;
  304.                   dirloc (xcur, ycur);
  305.                   dirstr (s); direol(); }
  306.           scrloc(); break;
  307.  
  308.            case KTAB: /* Tab - ignores insert */
  309.           xcur += (TABS    - (xcur    - 1) % TABS);
  310.           if (xcur >= WIDTH) xcur = WIDTH; scrloc(); break;
  311.  
  312.            case KINS: /* insert toggle */
  313.            dirloc (WIDTH - 9, 1); dirstr (iflag ? "    " : "I");
  314.            iflag ^=    0x01; break;
  315.  
  316.            case KQAC: /* Q cursor action */
  317.           edcheck(); undel();
  318.           if (xcur != 1) xcur =    1;
  319.           else if (ycur    != TOPROW) ycur    = TOPROW;
  320.           else for (q =    sline, ycur = TOPROW; ycur < ENDROW;
  321.                 q =    q->rptr, ++ycur) if (q == bfe) break;
  322.           scrloc(); break;
  323.  
  324.            case KF3: /* Break line */
  325.           if (tflag) break;
  326.           if (curline()    == bfe)    break;
  327.           if (!testful (0))
  328.           {  if    (!eflag    && xcur    == 1)
  329.              {    cset();    q = bufins ("\0", curline());
  330.             if (ycur == TOPROW) sline = q;
  331.             dirlins    (ycur);    }
  332.              else
  333.              {    if (curline() == mline)    { bell(); break; }
  334.             edset(); f = setzz (&s,    xcur, 0);
  335.             if (!f || eline->rptr != bfe)
  336.                bufins (f ? "\0" : s, eline->rptr);
  337.             *s = 0;    dirloc (xcur, ycur); direol();
  338.             if (ycur < ENDROW)
  339.             {  dirlins (1 +    ycur); dirloc (1, 1 + ycur);
  340.                dirstr (eline->rptr + 1); } } }
  341.           xcur = 1; dncurs(); break;
  342.  
  343.            case KRET: /* Ret */
  344.           if (tflag) { topclr(); edbuf [tcur] =    0;
  345.                    strcpy (cmdbuf, edbuf + 1);
  346.                    tflag = 0; return; }
  347.           if (!testful (0))
  348.           {  if    (iflag)
  349.              {    cset();    q = curline();
  350.             r = bufins ("\0", q->rptr);
  351.             if (q == bfe) q    = r;
  352.             if (ycur < ENDROW) dirlins (1 +    ycur); }
  353.              else { if ((q = curline())    == bfe)
  354.                 {  cset(); q = bufins ("\0", bfe); } }
  355.              if    (sline == bfe) sline = q; }
  356.           /* Continue as KF6 */
  357.  
  358.            case KF6:  /* CR    LF */
  359.           xcur = 1; dncurs(); break;
  360.  
  361.            case KGOMK: /* Go to mark */
  362.           if (mline == NULL) break;
  363.           edcheck(); undel();
  364.           redis    (mline); raster    (TOPROW); break;
  365.  
  366.  
  367.            case KSRCH: /* Search/replace string */
  368.           if (tflag) { topclr(); edbuf [tcur] =    0;
  369.                    strcpy (schbuf, edbuf + 1); tflag = 0; }
  370.           else edcheck(); undel();
  371.  
  372.           if ((q = curline()) == bfe)
  373.           {  toptxt ("Cannot find."); break; }
  374.           if (*schbuf == RCHAR || *schbuf == 0)
  375.           {  toptxt ("No search    string."); break; }
  376.           v = 0; unpack    (q + 1,    edbuf);
  377.           if (!setzz (&s, xcur + 1, 0))
  378.           {  if    ((k = sfind (s,    schbuf)) >= 0)
  379.              {    xcur +=    (k + 1); v = 1;    } }
  380.           if (!v)
  381.           {  toptxt (schbuf);
  382.              while ((q = q->rptr) != bfe)
  383.              {    unpack (q + 1, edbuf);
  384.             if ((k = sfind (edbuf, schbuf))    >= 0)
  385.             {  xcur    = (k + 1); redis (q);
  386.                v = 1; break; } } }
  387.           if (v) topclr(); else    { toptxt ("Cannot find."); break; }
  388.  
  389.           v = 0; for (s    = schbuf; *s; ++s) if (*s == RCHAR) break;
  390.           if (*s && q != mline)
  391.           {  k = s++ - schbuf; edset();
  392.              t = edbuf + (xcur - 1);
  393.              strcpy (u = t + k + WIDTH + 2, t +    k);
  394.              while (*s && *s !=    RCHAR) *t++ = *s++;
  395.              while (*u)    *t++ = *u++;
  396.              if    (t > endz) { t = endz; v = 1; }
  397.              *t    = 0; edcheck();    }
  398.           raster (TOPROW); if (v) bell(); break;
  399.  
  400.            case KRFSH: /* Refresh screen */
  401.           edcheck(); raster (TOPROW); break;
  402.  
  403.            case KTLIN: /* command entry */
  404.           topclr();
  405.           if (tflag ^= 0x1)
  406.           { edcheck(); tcur = 1;
  407.             edbuf [0] =    '>'; topdis(); }
  408.           break;
  409.  
  410.            case KSAVE: case    KQUIT:
  411.           edcheck();
  412.           strcpy (cmdbuf, c == KQUIT ? "quit" :    "end");
  413.           return;
  414.  
  415.        }  /* End of    topline    switch */
  416.  
  417.        if (tflag) continue;
  418.  
  419.        switch (c)  /* Non-topline actions */
  420.  
  421.        {   case KDEOL: /* Delete to    end of line */
  422.           if ((q = curline()) == bfe) break;
  423.           if (q    == mline) { bell(); break; }
  424.           edset(); t = edbuf + (xcur - 1); *t =    0;
  425.           dirloc (xcur,    ycur); direol(); break;
  426.  
  427.            case KCONC: /* concatenate lines    */
  428.           cset(); edcheck(); undel();
  429.           if (testful (0) || xcur >= WIDTH ||
  430.              (q    = curline()) ==    bfe) break;
  431.           if (q    == mline || q->rptr == mline) {    bell();    break; }
  432.           if (q->rptr != bfe)
  433.           {  edset(); f    = setzz    (&s, xcur, 1);
  434.              if    (!f) setrc (&t,    s); else t = s;
  435.              q = eline->rptr; unpack (q    + 1, t);
  436.              eline->rptr = q->rptr; q->rptr->lptr = eline;
  437.              if    (q != bfe) nfree (q);
  438.              f = setzz (&s, WIDTH + 1, 0);
  439.              if    (!f) { setrc (&t, s); *t = 0;
  440.                    do *(t+2) = *t; while (--t >= s);
  441.                    bufins (s + 2, eline->rptr); }
  442.              *s    = 0; edcheck();    }
  443.           else if (xcur    == 1 &&    *(char *)(q + 1) == 0)
  444.           {  q->lptr->rptr = bfe; bfe->lptr = q->lptr;
  445.              if    (sline == q) sline = bfe; nfree    (q); }
  446.           raster (ycur); break;
  447.  
  448.            case KBDEL: /* line delete and store */
  449.           cset(); edcheck(); q = curline(); pflag = 0;
  450.           if (sdel == NULL)
  451.             sdel = cdel    = (q ==    mline) ? NULL :    q;
  452.           else if (q !=    cdel->rptr)
  453.             {  r = sdel->rptr;
  454.                while (sdel != cdel)
  455.                {  nfree    (sdel);    sdel = r;
  456.               r = r->rptr; }
  457.                sdel = cdel = (q    == mline) ? NULL : q; }
  458.           else if (q !=    bfe)
  459.             {  if (q ==    mline) cdel->rptr = q->rptr;
  460.                else cdel = q; }
  461.           if (sdel == bfe)
  462.           { sdel = cdel    = NULL;    nprin(); break;    }
  463.           q->lptr->rptr    = q->rptr;
  464.           q->rptr->lptr    = q->lptr;
  465.           if (q    == mline) { nfree (mline); mline = NULL; }
  466.           if (q    == sline) sline    = q->rptr;
  467.           dirldel (ycur); q = sline;
  468.           for (i = TOPROW; i < ENDROW; ++i) q =    q->rptr;
  469.           dirloc (1, ENDROW); dirstr (q    + 1);
  470.           nprin(); break;
  471.  
  472.            case KBRES: /* buffer restore */
  473.           cset(); edcheck(); undel();
  474.           if (sdel == NULL || testful (0)) break;
  475.           pflag    = 0;
  476.           if ((q = curline()) == bfe)
  477.                q = bufins ("\0", bfe);
  478.           if (sline == bfe) sline = q;
  479.           for (r = sdel; ; r = r->rptr)
  480.           {  if    (testful (0)) break;
  481.              unpack (r + 1, edbuf);
  482.              q = bufins    (edbuf,    q->rptr);
  483.              if    (r == cdel) break; }
  484.           nprin(); raster (ycur); break;
  485.  
  486.            case KMARK: /* Set mark */
  487.           edcheck(); undel(); q    = curline();
  488.           q = bufins (mark, q->rptr);
  489.           if (mline != NULL)
  490.           {  mline->lptr->rptr = mline->rptr;
  491.              mline->rptr->lptr = mline->lptr;
  492.              nfree (mline); }
  493.           sline    = mline    = q;
  494.           if (ycur < ENDROW) ++ycur;
  495.           for (i = TOPROW; i < ycur; i++)
  496.             sline = sline->lptr;
  497.           if (sline == bfs)
  498.           { sline = bfs->rptr; --ycur; }
  499.           raster (TOPROW); break;
  500.  
  501.            case KTWRD:
  502.           if ((q = curline()) == bfe) break;
  503.           edcheck(); f = 0; q =    curline();
  504.           for (i = 1, t    = q + 1; *t; ++t)
  505.             i += (*t < 0x20) ? *t : 1;
  506.           if (xcur >= i)
  507.           {  xcur = f =    1; dncurs();
  508.              if    ((q = curline()) == bfe) break;    }
  509.           unpack (q + 1, edbuf); t = edbuf + (xcur - 1);
  510.           if (!f) while    (isalnum (*t)) { ++t; ++xcur; }
  511.           while    (*t && !isalnum    (*t)) {    ++t; ++xcur; }
  512.           scrloc(); break;
  513.  
  514.     } } /* End of edit switch */
  515.      }    /* End of keyedit */
  516.  
  517.  
  518. /* Cmdloop and keyedit support routines    */
  519.  
  520. /* Set pointer to x in edbuf; return 1 if beyond eol */
  521. setzz (s, x, f)    char **s;
  522.      {    static int v; static char *t;
  523.     *s = edbuf + (x    - 1);
  524.     for (v = 0, t =    edbuf; t <= *s;    t++)
  525.     { if (*t == 0) v = 1;
  526.       if (f    && v) *t = ' ';    }
  527.     return v; }
  528.  
  529. /* Set after last non-blank char */
  530. setrc (t, e) char **t, *e;
  531.      {    *t = e;    while (**t) ++*t;
  532.     while (*t > e && *(*t-1) == ' ') --*t; }
  533.  
  534. /* Get cursor line */
  535. curline()
  536.      {    static int i; static mtag *p;
  537.     for (p = sline,    i = TOPROW;
  538.          i < ycur; i++) p =    p->rptr;
  539.     return p; }
  540.  
  541. /* Cursor down one line    */
  542. dncurs()
  543.      {    static mtag *q;
  544.     edcheck(); undel();
  545.     if ((q = curline()) == bfe) return;
  546.     if (ycur < ENDROW) ++ycur;
  547.     else {    dirldel    (TOPROW); dirloc (1, ENDROW);
  548.         dirstr (q->rptr    + 1); sline = sline->rptr; }
  549.     scrloc(); }
  550.  
  551. /* Unlink deleted lines    buffer */
  552. undel()    { if (cdel) cdel->rptr = 0; }
  553.  
  554. /* Set change flag */
  555. cset() { cflag = 1; }
  556.  
  557.  
  558. /* Find    string t within    buffer b */
  559. sfind (b, t) char *b, *t;
  560.      {    static char *s,    *x; s =    b; x = t;
  561.     /* for (s = b; *s; ++s)
  562.        {  for (v = 1, x = s, y = t;
  563.           (*y && *y != RCHAR); ++x, ++y)
  564.         if (*x != *y) {    v = 0; break; }
  565.           if (v) return s -    b; }
  566.        return -1; }    */
  567.  
  568.     inline ( 0x8B, 0x36, &s,   0x8B, 0x16, &x,   0x8A, 0x04,
  569.          0x08, 0xC0, 0x74, 0x19, 0x89, 0xF3, 0x89, 0xD7,
  570.          0x8A, 0x05, 0x08, 0xC0, 0x74, 0x11, 0x3C, RCHAR,
  571.          0x74, 0x0D, 0x3A, 0x07, 0x75, 0x04, 0x43, 0x47,
  572.          0xEB, 0xEE, 0x46, 0xEB, 0xE1, 0x31, 0xF6,
  573.          0x89, 0x36, &s    );
  574.     return s ? s - b : -1; }
  575.  
  576.  
  577. /* Line    edit buffer handling routines */
  578.  
  579. /* Unpack cursor line to the edit buffer */
  580. edset()
  581.      {    static int i; static char *t, *x;
  582.     cset();    if (eflag) return; eflag = 1;
  583.     if ((eline = curline())    == bfe)
  584.          eline = bufins ("\0", bfe);
  585.     if (sline == bfe) sline    = eline;
  586.     unpack (eline +    1, edbuf); }
  587.  
  588. /* Reload edited line to buffer    */
  589. edcheck()
  590.      {    static mtag *q;
  591.     if (!eflag) return; eflag = 0;
  592.     q = bufins (edbuf, eline->rptr);
  593.     eline->lptr->rptr = eline->rptr;
  594.     eline->rptr->lptr = eline->lptr;
  595.     if (sline == eline) sline = q;
  596.     nfree (eline); }
  597.  
  598. /* Insert string s next    before buffer line p -
  599.    exits on overflow or    returns    pointer    to inserted line */
  600. bufins (s, p) char *s; mtag *p;
  601.      {    static mtag *q;    static int n;
  602.     static char *t,    *x;
  603.     n = pack (s, endz + 2);
  604.     if ((q = nalloc    (n + 1)) == NULL)
  605.     {  cls (1); putstr ("\nEdit aborted - buffer overflow.\n");
  606.       _exit    (0xFF);    }
  607.     strcpy (q + 1, endz + 2);
  608.     q->lptr    = p->lptr; q->rptr = p;
  609.     return p->lptr = p->lptr->rptr = q; }
  610.  
  611. /* Pack    line */
  612. pack   (s, d) char *s, *d;
  613.      {    static int c, f; static    char *t, *e; t = s; e =    d;
  614.      /*    f = 0; while (1)
  615.     {  if ((c = *s++) == 0)    { if (f) *d++ =    f; *d =    0; break; }
  616.        else    if (c >    0x20)  { if (f)    *d++ = f; f = 0; *d++ =    c; }
  617.        else    if (++f    == 0x1F) {*d++ = f; f =    0; } }    return d - e; }    */
  618.  
  619.     inline ( 0x8B, 0x36, &t,   0x8B, 0x3E, &e,   0x30, 0xC9,
  620.          0x8A, 0x04, 0x46, 0x3C, 0x20, 0x74, 0x10, 0x72, 0x1C,
  621.          0x08, 0xC9, 0x74, 0x05, 0x88, 0x0D, 0x47, 0x30, 0xC9,
  622.          0x88, 0x05, 0x47, 0xEB, 0xE9,
  623.          0xFE, 0xC1, 0x80, 0xF9, 0x1F, 0x72, 0xE2,
  624.          0x88, 0x0D, 0x47, 0x30, 0xC9, 0xEB, 0xDB,
  625.          0x08, 0xC9, 0x74, 0x05, 0x88, 0x0D, 0x47, 0x30, 0xC9,
  626.          0xC6, 0x05, 0x00, 0x89, 0x3E, &e );
  627.     return e - d; }
  628.  
  629. /* Unpack line for spaced output */
  630. unpack (s, d) char *s, *d;
  631.      {    static int c; static char *t, *e; t = s; e = d;
  632.      /*    while (1)
  633.     {  if ((c = *s++) == 0)    { *d = 0; break; }
  634.        else    if (c >    0x20) *d++ = c;
  635.        else    while (c--) *d++ = 0x20; } return d - e; } */
  636.  
  637.     inline ( 0x8B, 0x36, &t,   0x8B, 0x3E, &e,
  638.          0x8A, 0x04, 0x46, 0x08, 0xC0, 0x74, 0x13,
  639.          0x3C, 0x20, 0x72, 0x05,
  640.          0x88, 0x05, 0x47, 0xEB, 0xF0,
  641.          0xC6, 0x05, 0x20, 0x47, 0xFE, 0xC8,
  642.          0x75, 0xF8, 0xEB, 0xE6,
  643.          0x88, 0x05, 0x89, 0x3E, &e );
  644.     return e - d; }
  645.  
  646. /* Unpack line for tabbed output */
  647. untpak (s, d) char *s, *d;
  648.      {    static char *e,    *p; e =    d; p = s;
  649.     /* while (1)
  650.        {  while ((c    = *p) && c >  0x20)
  651.            {  *d++ = c; ++p; ++k; }     t1 = k;
  652.           while ((c    = *p) && c <= 0x20)
  653.            {  k += (c == 0x20) ? 1 : c; ++p; }
  654.           if (!c) break; t2    = k / 8;
  655.           for (i = t1 / 8; i < t2; ++i) *d++ = '\t';
  656.           t2 *= 8; t1 = (t2    > t1) ?    t2 : t1;
  657.           for (i = t1; i < k; ++i) *d++ = '    '; }  */
  658.  
  659.     inline ( 0x8B, 0x1E, &p,   0x8B, 0x3E, &e,   0x31, 0xC9,
  660.          0x31, 0xC0, 0x8A, 0x07, 0x08, 0xC0, 0x74, 0x0B,
  661.          0x3C, 0x21, 0x72, 0x07, 0x88, 0x05, 0x43, 0x47, 0x41,
  662.          0xEB, 0xED, 0x89, 0xCA, 0x8A, 0x07, 0x08, 0xC0,
  663.          0x74, 0x0F, 0x3C, 0x21, 0x73, 0x0B, 0x3C, 0x20,
  664.          0x75, 0x02, 0xB0, 0x01, 0x01, 0xC1, 0x43,
  665.          0xEB, 0xEB, 0x08, 0xC0, 0x74, 0x2B,
  666.          0x89, 0xD0, 0x25, 0xF8, 0xFF, 0x89, 0xCE,
  667.          0x81, 0xE6, 0xF8, 0xFF, 0x39, 0xF0, 0x73, 0x09,
  668.          0xC6, 0x05, 0x09, 0x47, 0x05, 0x08, 0x00, 0xEB, 0xF3,
  669.          0x39, 0xD0, 0x72, 0x02, 0x89, 0xC2, 0x39, 0xCA,
  670.          0x73, 0x07, 0xC6, 0x05, 0x20, 0x47, 0x42, 0xEB, 0xF5,
  671.          0xEB, 0xA7, 0x89, 0x3E, &e );
  672.     return e - d; }
  673.  
  674.  
  675. /* Edit    buffer handling    - all pointers are to the mtag header */
  676.  
  677. /* Allocate a new buffer line */
  678. nalloc (nb) unsigned nb;
  679.      {    static mtag *p,    *q; static unsigned nt;
  680.     if (!last)  /* reserve entire heap */
  681.     {  base.lptr = last = &base; base.size = 0;
  682.        p = * (mtag **) 0x100; q = *    (mtag **) 0x102;
  683.        nt =    q - p; p->size = nt - 2; nfree (p); }
  684.     nt = 1 + (nb + (sizeof (mtag) -    1)) / sizeof (mtag);
  685.     for (q = last, p = q->lptr; ; q    = p, p = p->lptr)
  686.          {    if (p->size >= nt)
  687.         {  if (p->size != nt)
  688.            { p->size -=    nt; p += p->size; p->size = nt;    }
  689.            else     q->lptr = p->lptr;
  690.            last    = q; testful (1); return p; }
  691.         if (p == last) return NULL;  }
  692.       }    /* End */
  693.  
  694. /* Free    memory line */
  695. nfree(b) mtag *b;
  696.      {    static mtag *p,    *q; p =    b;
  697.     for (q = last; ; q = q->lptr)
  698.         if ((q < p && q->lptr > p) ||
  699.         (q->lptr <= q &&
  700.         (p > q || p < q->lptr) )) break;
  701.     if (p +    p->size    != q->lptr) p->lptr = q->lptr;
  702.     else { p->size += q->lptr->size; p->lptr = q->lptr->lptr; }
  703.     if (q +    q->size    != p) q->lptr =    p;
  704.     else { q->size += p->size; q->lptr = p->lptr; }
  705.     last = q; testful (1); }
  706.  
  707. /* Set to print    buffer size */
  708. nprin()    { pflag    = 1; testful (1); }
  709.  
  710. /* Test/set edit buffer    full */
  711. testful    (f)
  712.      {    static mtag *p,    *q; static unsigned i, j, lb, nt =
  713.       1 + (WIDTH + 4 + (sizeof (mtag) - 1))    / sizeof (mtag);
  714.     if (!f && !bfull) return 0;
  715.     i = j =    0; lb =    bfull; p = last;
  716.     do { i += (p->size / nt);
  717.          j += (p->size - 1);
  718.          p = p->lptr; } while (p !=    last);
  719.     rfull =    (i < 30);
  720.     if (lb ^ (bfull    = (i < 4)))
  721.     {    dirloc (30, 1);
  722.          dirstr (bfull ? "Full!" : "     "); }
  723.     if (pflag) { dirloc (WIDTH - 5,    1);
  724.              dirdec (j * sizeof    (mtag)); }
  725.     if (!f && bfull) bell();
  726.     return bfull; }
  727.  
  728.  
  729. /* File    input/output */
  730.  
  731. /* Set file buffer and open file */
  732. bopen (i, s) char *s;
  733.      {    static int fd; static qbuf bb[2], *b;
  734.     if ((fd    = open (s, 0)) == -1) return NULL;
  735.     b = bb + i; b->qfd = fd; b->qnd    = 0; return b; }
  736.  
  737. /* Read    file to    buffer full */
  738. rdfile (fp, p) int *fp;    mtag *p;
  739.      {      pflag    = 0;
  740.       while    (!rfull)
  741.       {  inscline (fp);
  742.          if    (!*fp && *edbuf    == 0) break;
  743.          bufins (edbuf, p);    }
  744.       if (rfull) toptxt ("File unfinished.");
  745.       nprin(); }
  746.  
  747. /* Raw line input to edbuf - returns
  748.    *f =    0 and *edbuf = 0 at EOF    */
  749. inscline (f) qbuf **f;
  750.      {    static n, k, tbc; static char *s;
  751.     static qbuf *b;
  752.     s = edbuf; *s =    0; tbc = 1;
  753.     if (!(b    = *f)) return;
  754.     while (1)
  755.     {  if (s >= endz) { k =    0; break; }
  756.        if (b->qnx >= b->qnd)
  757.        {  if ((n = read (b->qfd, b->qbb, QBSIZE)) >    0)
  758.           b->qnd = (b->qnx = b->qbb) + n;
  759.           else { k = EOF;  break; }    }
  760.        /* k    = *(b->qnx)++; */ &b->qnx;
  761.        inline ( 0x8B, 0x3F,    0x47, 0x89, 0x3F, 0x4F,
  762.             0x8A, 0x1D,    0xB7, 0x00, 0x89, 0x1E,    &k );
  763.        if (    k == '\r' ) continue;
  764.        if (    k == '\n' ) break;
  765.        if (    k == '\t' )
  766.        /*  do { ++tbc; if (s < endz) *s++ =    ' '; }
  767.            while ( tbc % 8 != 1 ); */
  768.        inline ( 0xBE, &tbc,    0xBB, &s,   0x8B, 0x16,    &endz,
  769.             0xFF, 0x04,    0x8B, 0x3F, 0x39, 0xD7,    0x73, 0x05,
  770.             0xC6, 0x05,    0x20, 0xFF, 0x07, 0x8B,    0x04,
  771.             0x25, 0x07,    0x00, 0x3D, 0x01, 0x00,    0x75, 0xE9 );
  772.        else
  773.        /* {    ++tbc; k &= 0x7F;
  774.         *s++ = k + (k <    0x20 ? 0x40 : 0); } */
  775.        inline ( 0xBB, &tbc,    0xFF, 0x07, 0xBB, &s,
  776.             0xA1, &k,    0x24, 0x7F, 0x3C, 0x20,
  777.             0x73, 0x02,    0x04, 0x40, 0x8B, 0x3F,
  778.             0x88, 0x05,    0x47, 0x89, 0x3F );
  779.       }
  780.     *s = 0;    if (k <    0) { close ((*f)->qfd);    *f = 0;    }
  781.  
  782.      } /* End of inscline */
  783.  
  784.  
  785. /* Save    buffer lines s - t to file nm */
  786. fsave (nm, s, t, z) char *nm; mtag *s, *t;
  787.      {    static int e, f, v; static mtag    *q;
  788.     int unpack(), untpak(),    (*up)();
  789.     up = z ? unpack    : untpak;
  790.     if ((f = creat (nm, 0))    == -1)
  791.     {  toptxt ("Cannot open    "); dirstr (nm); return    -1; }
  792.     toptxt ("Saving: "); dirstr (nm);
  793.     for (v = 0, q =    s; q !=    t; q = q->rptr)
  794.     {  if (q == mline) continue;
  795.        e = (*up) (q    + 1, edbuf);
  796.        edbuf [e++] = 0x0D; edbuf [e++] = 0x0A;
  797.        if (write (f, edbuf,    e) != e)
  798.        {  toptxt ("Write error."); v = -1; break; }    }
  799.     if (close (f) == -1)
  800.     {  toptxt ("Cannot close "); dirstr (nm); return -1; }
  801.     return v; }
  802.  
  803.  
  804. /* Edit    screen display routines    */
  805.  
  806. /* Print screen    header layout */
  807. setscr()
  808.      {    static int i;
  809.     dirloc (WIDTH -    29, 1);    dirstr ("File: "); dirstr (scename);
  810.     dirloc (WIDTH -    9, 1); dirstr (iflag ? "I" : " ");
  811.     for (dirloc (1,    2), i =    1; i <=    WIDTH; i++)
  812.     dirstr (i % TABS == 1 ?    "+" : "-"); }
  813.  
  814. /* Display edit    raster from line n */
  815. raster (n)
  816.      {    static int i, j; static    mtag *q;
  817.     for (q = sline,    i = TOPROW; i <= ENDROW; q = q->rptr, ++i)
  818.     {  if (q == bfe    && ycur    > i) ycur = i;
  819.        if (i >= n) { dirloc    (1, i);    dirstr (q + 1);    direol(); }
  820.        for (j = 0; j < 80; j++); /*    DELAY */ }
  821.     scrloc(); }
  822.  
  823. /* Reset with edit line    p at screen line ycur */
  824. redis (p) mtag *p;
  825.      {    static int i; static mtag *q;
  826.     for (q = p, i =    TOPROW;    i < ycur; i++) q = q->lptr;
  827.     if ((sline = q)    == bfs)
  828.     for (q = sline = bfs->rptr, ycur = TOPROW;
  829.          q != p; q = q->rptr) ++ycur; }
  830.  
  831.  
  832. /* Topline display routines */
  833. topclr() { static int i, k = 1 + TWID /    4;
  834.        dirloc (i = 1, 1); while (i++ <= k) dirstr ("    ");    }
  835.  
  836. topdis() { strcpy (edbuf + tcur, "_ ");
  837.        dirloc (1, 1); dirstr (edbuf); }
  838.  
  839. toptxt(s) char *s;
  840.      { topclr(); dirloc (1,    1);
  841.        dirstr (s); clrct = TCLR; }
  842.  
  843.  
  844. /* Video and console output routines */
  845.  
  846. /* Clear screen, home cursor */
  847. cls (f)    { static int i,    xd, yd;
  848.       xd = xcur; yd    = ycur;
  849.       if (f) xcur =    ycur = 1; scrloc();
  850.       xcur = xd; ycur = yd;
  851.       for (i = 1; i    <= ENDROW; i++)
  852.       { dirloc (1, i); direol(); } }
  853.  
  854.  
  855. /* Move    cursor to xcur,    ycur (ANSI.SYS output) */
  856. scrloc()
  857.     { static char ss[] = "\33[00;00H";
  858.       ss[2]    = dig (ycur / 10); ss[3] = dig (ycur % 10);
  859.       ss[5]    = dig (xcur / 10); ss[6] = dig (xcur % 10);
  860.       putstr (ss); }
  861.  
  862. dig (n)    { return '0' + n + (n >    9 ? 7 :    0); }
  863.  
  864. /* Ring    the bell */
  865. bell()    { putstr ("\7"); }
  866.  
  867. /* Keyboard entry - wait for next character */
  868. getch()
  869.      {    static int c;
  870.     while (!(c = rawin()));    return c; }
  871.  
  872. /* Put string to stdout    - Bdos fn 6 to avoid Control-C */
  873. putstr (s) char    *s;
  874.      {    static char *t;    t = s;
  875.     inline ( 0x8B, 0x3E, &t,   0x31, 0xDB,
  876.          0x8A, 0x05, 0x47, 0x08, 0xC0, 0x75, 0x01,
  877.          0xC3, 0x43, 0x3C, 0x0A, 0x74, 0x08, 0x88,
  878.          0xC2, 0xB4, 0x06, 0xCD, 0x21, 0xEB, 0xEB,
  879.          0xB2, 0x0D, 0xB4, 0x06, 0xCD, 0x21,
  880.          0xB2, 0x0A, 0xB4, 0x06, 0xCD, 0x21, 0xEB, 0xDD    ); }
  881.  
  882.  
  883. /* Output decimal unsigned value v */
  884. dirdec (v) unsigned v;
  885.      {    static char b[]    = "           ", *s;
  886.     s = b +    5; ppd (v, &s);    *s = 0;    dirstr (s - 5);    }
  887.  
  888. ppd (n,    p) unsigned n; char **p;
  889.      {     if (n < 10) {    *(*p)++    = '0' +    n +
  890.             (n > 9 ? 7 : 0); return; }
  891.      ppd (n    / 10, p); ppd (n % 10, p); }
  892.  
  893.  
  894. /* Direct output to screen memory at B800:0 */
  895.  
  896. /* Set direct output cursor */
  897. dirloc(x, y) int x, y; { dircc = x + x + y * 0xA0 - 0xA2; }
  898.  
  899. /* Output packed or normal strings */
  900. dirstr (s) char    *s;
  901.      {    static char *ss; ss = s;
  902.     inline ( 0x8B, 0x1E, &ss,  0x8B, 0x3E, &dircc,
  903.          0x06, 0xB8, 0x00, 0xB8, 0x8E, 0xC0, 0x8A, 0x07,
  904.          0x43, 0x3C, 0x20, 0x72, 0x07, 0x26, 0x88, 0x05,
  905.          0x47, 0x47, 0xEB, 0xF2, 0x08, 0xC0, 0x74, 0x0C,
  906.          0x26, 0xC6, 0x05, 0x20, 0x47, 0x47, 0xFE, 0xC8,
  907.          0x75, 0xF6, 0xEB, 0xE2, 0x07, 0x89, 0x3E, &dircc ); }
  908.  
  909. /* Erase to end    of line    */
  910. direol()
  911.      {    static unsigned    nb; nb = (0xA0 - (dircc    % 0xA0)) >> 1;
  912.     inline ( 0x8B, 0x3E, &dircc,0x8B, 0x0E,    &nb,
  913.          0x06, 0xB8, 0x00, 0xB8, 0x8E, 0xC0, 0x26, 0xC6,
  914.          0x05, 0x00, 0x47, 0x47, 0xE2, 0xF8, 0x07 ); }
  915.  
  916. /* Insert cleared line n */
  917. dirlins    (n)
  918.      {    static int dd, nb;
  919.     if ( n < ENDROW    )
  920.     {  nb =    (ENDROW    - n) * 0x50;
  921.        inline ( 0xBE, (ENDROW-1) * 0xA0 - 2,  0xBF,    ENDROW * 0xA0 -    2,
  922.             0x8B, 0x0E,    &nb,  0x06, 0xB8, 0x00,    0xB8,
  923.             0x8E, 0xC0,    0x26, 0x8A, 0x04, 0x26,    0x88, 0x05,
  924.             0x4E, 0x4E,    0x4F, 0x4F, 0xE2, 0xF4,    0x07 );    }
  925.     dd = dircc; dirloc (1, n); direol(); dircc = dd; }
  926.  
  927. /* Delete line n and clear last    line */
  928. dirldel    (n)
  929.      {    static int dd, ns, nd, nb;
  930.     if ( n < ENDROW    )
  931.     {  ns =    n * 0xA0; nd = ns - 0xA0; nb = (ENDROW - n) * 0x50;
  932.        inline ( 0x8B, 0x36,    &ns,  0x8B, 0x3E, &nd,
  933.             0x8B, 0x0E,    &nb,  0x06, 0xB8, 0x00,    0xB8, 0x8E,
  934.             0xC0, 0x26,    0x8A, 0x04, 0x26, 0x88,    0x05,
  935.             0x46, 0x46,    0x47, 0x47, 0xE2, 0xF4,    0x07 );    }
  936.     dd = dircc; dirloc (1, ENDROW);    direol(); dircc    = dd; }
  937.  
  938.  
  939. /* End of Editor */
  940.  
  941. #include ?smio.lib?
  942.